/**
 * 
 */
package org.quickbundle.project.filter;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dom4j.Node;
import org.quickbundle.base.beans.factory.RmBeanFactory;
import org.quickbundle.config.RmLoadConfig;
import org.quickbundle.tools.support.log.RmLogHelper;
import org.slf4j.Logger;

import com.dfhc.ISystemConstant;
import com.dfhc.pub.service.PubParamService;
import com.dfhc.util.CryptoHelper;
import com.dfhc.util.StringHelper;

/**
 * @author 龙色波
 * 解密url过滤器
 */
public class DecryptionUrlFilter implements Filter {
	/**
	 * 可以明文访问的资源url正则集合，从rm.xml读取
	 */
	private static Set<String> sPlaintextUrl = new HashSet<String>();
	/**
	 * 双检锁标志，判断是否已从rm.xml初始化plaintextUrls配置完成
	 */
	private static volatile boolean isInitPlaintextUrlConf = false;
	private static byte[] lockPlaintextUrlConf = new byte[0];
    //开始url过滤
	private static final Logger logUrl = RmLogHelper.getLogger("url");
	@Override
	public void destroy() {
		
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain filterChain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse res = (HttpServletResponse) response;
		//获取url
		String uri = req.getRequestURI();
		boolean isDebug = getPubParamService().isDebugDecryptUrl();
		StringBuilder fullUrl = new StringBuilder();
		//log url
		fullUrl.append(uri);
		if (req.getQueryString() != null) {
			fullUrl.append("?");
			fullUrl.append(req.getQueryString());
		}
		if(isDebug){
			logUrl.debug(fullUrl.toString());
		}
		String shortUri = uri.substring(req.getContextPath().length());
		 //如果是需要明文url或者已经解密过，不用解密
		if(ISystemConstant.DICTIONARY_RM_YES_NOT_1.equals((String)req.getAttribute(ISystemConstant.UNNECESSARY_DECRYPT))||setContainMatchString(sPlaintextUrl, shortUri)) {
			if(isDebug){
				System.out.println("url:"+shortUri+",不用解密或者已经解密过!");
				//String attribute = (String)req.getAttribute(ISystemConstant.UNNECESSARY_DECRYPT);
				//System.out.println(attribute);
			}
			filterChain.doFilter(request, response);
		}else{
			//解密url,只解密问号之前url
			String plaintextUrl = shortUri;
			if(shortUri.contains("?")){
				plaintextUrl = shortUri.substring(0,shortUri.indexOf('?'));
			}
			//如果是以/开头，则去掉/
			if(plaintextUrl.startsWith("/")){
				plaintextUrl = plaintextUrl.substring(1);
			}
			try {
				
				plaintextUrl = CryptoHelper.decryptUrl((HttpServletRequest) request, plaintextUrl);
				if(isDebug){
					System.out.println("解密url:"+shortUri+"成功，解密后url:"+plaintextUrl);
				}
				req.setAttribute(ISystemConstant.UNNECESSARY_DECRYPT, ISystemConstant.DICTIONARY_RM_YES_NOT_1);
//				RequestDispatcher rd = request.getRequestDispatcher(plaintextUrl);
//				rd.forward(request, response); 
				//附帶已解密標誌
//				if(StringHelper.findStrNum(plaintextUrl, "?")>0){
//					plaintextUrl = plaintextUrl+"&"+ISystemConstant.UNNECESSARY_DECRYPT+"="+ISystemConstant.DICTIONARY_RM_YES_NOT_1;
//				}else{
//					plaintextUrl = plaintextUrl+"?"+ISystemConstant.UNNECESSARY_DECRYPT+"="+ISystemConstant.DICTIONARY_RM_YES_NOT_1;
//				}
//				filterChain.doFilter(new ForwardingURLRequestWrapper((HttpServletRequest) request,plaintextUrl),response);
				DispatcherWrapper reqWrapper = new DispatcherWrapper((HttpServletRequest) request);
	    		if (reqWrapper.getAttribute(ISystemConstant.FILTER_FORWARD) == null) {
	                // 设置参数
	    			reqWrapper.setAttribute(ISystemConstant.FILTER_FORWARD, Boolean.TRUE);
	                // 请求分发
	                try{
	                	response.setCharacterEncoding(ISystemConstant.ENCODE_UTF_8);
	                	response.setContentType(ISystemConstant.CONTENT_TYPE); 
	                	request.setCharacterEncoding(ISystemConstant.ENCODE_UTF_8);
	                	//String parameter = request.getParameter("courseName");
	                	//System.out.println(parameter);
	                	request.getRequestDispatcher(plaintextUrl).forward(reqWrapper, response);
	        		}catch(Exception e){
	        			e.printStackTrace();
	        			res.sendRedirect(req.getContextPath() + "/jsp/util/prohibitedExceedsAuthorizedAccess.jsp");
	        		}
	                
	            } else {
	                // 设置为false防止请求进入死循环
	                req.setAttribute(ISystemConstant.FILTER_FORWARD, Boolean.FALSE);
	                filterChain.doFilter(request, response);
	            }
			} catch (Exception e) {
				e.printStackTrace();
				if(isDebug){
					System.out.println("解密url:"+shortUri+"失败!");
				}
				res.sendRedirect(req.getContextPath() + "/jsp/util/prohibitedExceedsAuthorizedAccess.jsp");
			}
//			filterChain.doFilter(request, response);
		}
		if(isDebug){
			System.out.println("DecryptionUrlFilter doFilter...");
		}
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
			doInitConfig();		
	}
	/**
	 * 初始化配置
	 */
	private void doInitConfig() {
		if(!isInitPlaintextUrlConf) { //双检锁初始化
			synchronized (lockPlaintextUrlConf) {
				if(!isInitPlaintextUrlConf) {
					List<Node> lUrl = RmLoadConfig.getRmDoc().selectNodes("/rm/org.quickbundle.project.filter.RmPrivilegeFilter/plaintextUrls/url");
					for(Node node : lUrl) {
						sPlaintextUrl.add(node.getText().trim());
					}
					isInitPlaintextUrlConf = true;
				}
			}
		}
	}
	/**
	 * 功能: 判断Set中是否有使str符合的正则匹配值
	 *
	 * @param set
	 * @param str
	 * @return
	 */
	private boolean setContainMatchString(Set<String> set, String url) {
	    if(set == null) {
	        return true;
	    }
	    for (String p : set) {
            if(!url.matches(p)) {
            	continue;
            }            
            return true;
        }
	    return false;
	}
	/**
     * 得到Service对象
     * 
     * @return Service对象
     */
    public PubParamService getPubParamService() {
        return (PubParamService) RmBeanFactory.getBean(PubParamService.class.getName());  //得到Service对象,受事务控制
    }	
}
